#pragma once
#include <unordered_map>
#include <string_view>
#include <utility>
#include <vector>
#include <string>
#include <memory>

#include "setting.hpp"
#include "log.hpp"

namespace ns_interface
{
    // http协议基类
    class http_base
    {
    protected:
        // 报文完整性控制结构体
        struct completeness_control
        {
            completeness_control();

            // 重置结构体
            void reset();

            // 请求头/响应头缓冲区
            std::string _buf;
            // 本条请求头/响应头是否完整
            bool _is_cur_header_completed;
            // 请求头/响应头键值
            std::string_view _key;
            // 目标载荷字节数
            unsigned long long _final_content_size = 0;
            // 已写入载荷字节数
            unsigned long long _cur_content_size = 0;
            // 解析进度
            unsigned int _progress;
        };
    public:
        // 将生存期太短的字符串放入内部存储
        void headerStorge(std::string_view key, bool storge_key, std::string_view value, bool storge_value);
    protected:
        http_base();
        virtual ~http_base();

        // 解析请求行/状态行
        bool parseTitle(std::string::iterator& begin, const std::string::iterator& end, std::string& parsed_str);

        // 解析请求头/响应头
        bool parseHeader(std::string::iterator& begin, const std::string::iterator& end);

        // 解析请求载荷/响应载荷
        bool parseContent(std::string::iterator& begin, const std::string::iterator& end);

        // 拼接式序列化
        void serialize(std::vector<std::string_view>& ret, std::array<std::string_view, 3> input) const;

        // 离散式序列化
        void serialize_sp(std::string& ret, std::array<std::string_view, 3> input) const;

        // 重置
        void clear();

        // 视图->数字
        unsigned long long toInteger(const std::string_view& number_str);
    public:
        // 请求头/响应头表
        std::unordered_map<std::string_view, std::string_view> _header_table;
        // 请求载荷/响应载荷
        std::string _content;
    public:
        // 拓展名转换表
        const static std::unordered_map<std::string_view, std::string_view> _msg_type;
    protected:
        // 请求头/响应头存储
        std::vector<std::shared_ptr<std::string>> _header_array;
        // 报文完整性控制
        completeness_control _ctrl;
    protected:
        // http空行
        constexpr static const char* _blank = "\r\n";
        // http请求头/响应头分隔符
        constexpr static const char* _header_blank = ": ";
        // http请求行/响应行分隔符
        constexpr static const char* _space = " ";
    };

    // http请求
    class http_request : public http_base
    {
    public:
        http_request();

        // 请求解析
        bool parse(std::string::iterator begin, std::string::iterator end);

        // 拼接式序列化
        std::vector<std::string_view> serialize() const;

        // 离散式序列化
        std::string serialize_sp() const;

        // 清除内容
        void clear();
    public:
        // 请求方法
        std::string _method;
        // 请求资源
        std::string _url;
        // 发送者http版本号
        std::string _version;
    };

    // http响应
    class http_response : public http_base
    {
    public:
        http_response();

        // 响应解析
        bool parse(std::string::iterator begin, std::string::iterator end);

        // 拼接式序列化
        std::vector<std::string_view> serialize() const;

        // 离散式序列化
        std::string serialize_sp() const;

        // 清除内容
        void clear();
    public:
        // 发送者http版本号
        std::string _version;
        // 响应状态码
        std::string _code;
        // 响应状态字符串
        std::string _status;
    };

    // url解析
    class url
    {
    public:
        url(const std::string& input = "/");
        url& operator=(const std::string& input);
    private:
        // 解析url
        void parse(const std::string& input);

        // url解密
        static std::string url_decode(const std::string& encoded);

        // url解密
        static std::string url_decode(const std::string_view& encoded);
    public:
        // 请求资源路径
        std::filesystem::path _resourse_path;
        // 请求资源拓展名
        std::string _extension;
        // 请求资源参数表
        std::unordered_map<std::string, std::string> _parameters;
    };
}